package com.combetter.changxing.bluetooth;

import android.bluetooth.BluetoothGatt;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.ArrayMap;

import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.combetter.changxing.MyApplication;
import com.combetter.changxing.bluetooth.model.Cigarette;
import com.combetter.changxing.bluetooth.model.EventMessage;
import com.combetter.changxing.db.Facility;
import com.combetter.changxing.db.entity.User;
import com.combetter.changxing.utils.ASCUtils;
import com.combetter.changxing.utils.AppUtils;
import com.combetter.changxing.utils.DateUtils;
import com.combetter.changxing.utils.LogUtil;
import com.combetter.changxing.utils.MD5Utils;
import com.combetter.changxing.utils.SPUtils;
import com.combetter.changxing.utils.ToastUtils;
import com.google.gson.Gson;

import org.greenrobot.eventbus.EventBus;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;


/**
 * Created by Mark.fan on 2018/6/28.
 */

public class FacilityClient2 {
    //1.鉴权成功后才可进行下一步指令发送，每5分钟鉴权一次，处理每次鉴权状态，鉴权失败则再次鉴权，三次鉴权失败则停止鉴权，但提示，显性鉴权和隐性鉴权

    //鉴权成功后按顺序发送指令，每次指令发送三次

    private final int DEVICE_START_CONNECT = 0;//设备开始链接
    private final int DEVICE_START_CONNECT_FAIL = 404;//连接失败
    private final int DEVICE_START_DISCONNECT_FAIL = 504;//连接断开
    private final int DEVICE_START_RECONNECT = 505;//重连
    private final int DEVICE_START_AUTH = 100;//开始鉴权
    private final int DEVICE_START_AUTH_AGAIN = 101;//再次鉴权
    private final int DEVICE_AUTH_SUC = 200;//鉴权成功
    private final int DEVICE_AUTH_FAIL = 500;//鉴权失败


    private final int DEVICE_GET_1 = 1;//发送2成功后返回
    private final int DEVICE_SEND_2 = 2;//发送MD5原始字符-->返回 DEVICE_GET_1
    private final int DEVICE_SEND_3 = 3;//获取MD5运算后的字符；手机发给设备
    private final int DEVICE_GET_4 = 4;//返回MD5运算后的字符；设备发给手机
    private final int DEVICE_SEND_5 = 5;//获取MD5原始字符；手机发给设备
    private final int DEVICE_GET_6 = 6;//返回MD5原始字符；设备发给手机
    private final int DEVICE_SEND_7 = 7;//发送运算后的MD5字符；手机发给设备


    private final int DEVICE_SEND_08 = 8;//发送香烟类型编号
    private final int DEVICE_SEND_09 = 9;//获取设备的香烟抽吸数据
    private final int DEVICE_GET_0A = 10;//返回设备的香烟抽吸数据
    private final int DEVICE_SEND_11 = 11;//获取剩余电量值

    private final int DEVICE_GET_12 = 12;//返回剩余电量值
    private final int DEVICE_SEND_13 = 13;//设备名称发送；手机发给设备
    private final int DEVICE_SEND_14 = 14;//发送发热温度微调值
    private final int DEVICE_SEND_14_SUC = 141;//发送发热温度微调值
    private final int DEVICE_SEND_16 = 16;//发送预热时间微调值
    private final int DEVICE_SEND_16_SUC = 161;//发送预热时间微调值
    private final int DEVICE_SEND_17 = 17;//发送日期和时间值
    private final int DEVICE_SEND_18 = 18;//获取预热时间
    private final int DEVICE_GET_19 = 19;//预热时间（以秒为单位），预热温度（以℃为单位，高位在前），加热时间（以秒为单位），加热温度（以℃为单位，高位在前）。
    private final int DEVICE_SEND_1A = 20;//获取设备的固件版本号
    private final int DEVICE_GET_1B = 21;//返回固件版本号
    private final int DEVICE_GET_1C = 22;//返回设备的香烟抽吸数据完成
    private final int DEVICE_SEND_1D = 23;//发送香烟抽吸数据接收完成
    private final int DEVICE_SEND_1E = 24;//发送香烟的显示名称

    private static FacilityClient2 mClient;

    public BleDevice bleDevices;

    private boolean mIsAuthAfter = false;

    public  static int reConnectTimes = 0;

    //香烟抽吸数据
    private List<Cigarette> cigarettes = new ArrayList<>();

    private SPUtils utils = new SPUtils(MyApplication.getInstance());


    public static FacilityClient2 getClient() {
        buffer = new StringBuffer();

        if (mClient == null) {
            synchronized (FacilityClient2.class) {
                if (mClient == null) {
                    mClient = new FacilityClient2();
                }
            }
        }
        return mClient;
    }

    //蓝牙UUID
    /**
     * 进行通信的服务UUID
     */
    public final static String SERVICE_UUID = "00010203-0405-0607-0809-0a0b0c0d1910";
    /**
     * notify or read UUID
     */
    public final static String CHAR_READ_UUID = "00010203-0405-0607-0809-0a0b0c0d2b10";
    /**
     * write and no response UUID
     */
    public final static String CHAR_WRITE_UUID = "00010203-0405-0607-0809-0a0b0c0d2b11";
    public final static String DESC_UUID = "00002902-0000-1000-8000-00805f9b34fb";

    /**
     * 获取md5加密码后，0，2，4，5，6，6上的位置
     */
    public static byte[] REQUEST_SPACHIL_CHAR = new byte[]{(byte) 0x00, (byte) 0x02, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x06};

    /**
     * 状态，0：成功；1：错误；
     */
    public final static byte CMD_RESPONSE_STATU = (byte) 0x01;
    /**
     * 发送md5原始字符
     */
    public final static byte CMD_REQUEST_RAW_STR = (byte) 0x02;

    /**
     * 发送md5加密后的字符
     */
    public final static byte CMD_REQUEST_MD5_STR = (byte) 0x03;

    /**
     * 返回md5加密后字符
     */
    public final static byte CMD_RESPONSE_MD5_STR = (byte) 0x04;

    /**
     * 获取md5原始字符
     */
    public final static byte CMD_REQUEST_RAW_STR2 = (byte) 0x05;

    /**
     * 返回md5原始字符
     */
    public final static byte CMD_RESPONSE_RAW_STR2 = (byte) 0x06;

    /**
     * 发送运算后的md5字符
     */
    public final static byte CMD_SEND_MDT_STR = (byte) 0x07;

    /**
     * 发送香烟类型编号
     */
    public final static byte CMD_SEND_TYPE_NUMBER = (byte) 0x08;

    /**
     * 获取设备的香烟抽吸数据
     */
    public final static byte CMD_REQUEST_TYPE = (byte) 0x09;

    /**
     * 返回设备的香烟抽吸数据
     */
    public final static byte CMD_RESPONSE_TYPE = (byte) 0x0A;

    /**
     * 确定设备的香烟抽吸数据发送完成
     */
    public final static byte GET_SUCCESS = (byte) 0x1C;

    /**
     * 发送确定收到香烟抽吸数据完成
     */
    public final static byte SEND_SUCCESS = (byte) 0x1D;

    /**
     * 获取设备剩余电量值
     */
    public final static byte CMD_REQUEST_BATTERY = (byte) 0x11;

    /**
     * 返回设备剩余电量值
     */
    public final static byte CMD_RESPONSE_BATTERY = (byte) 0x12;

    /**
     * 发送设备名称
     */
    public final static byte CMD_SEND_NAME = (byte) 0x13;

    /**
     * 发送发热温度微调值
     */
    public final static byte CMD_SEND_FEVER = (byte) 0x14;


    /**
     * 发送预热时间微调值
     */
    public final static byte CMD_PREHEAT_TIME = (byte) 0x16;

    /**
     * 发送日期和时间值
     */
    public final static byte CMD_SEND_DATE = (byte) 0x17;
    /**
     * 获取预热时间
     */
    public final static byte CMD_PREHEAT = (byte) 0x18;
    /**
     * 返回预热时间和加热温度
     */
    public final static byte CMD_GET_PREHEAT = (byte) 0x19;
    /**
     * 发送命令获取版本号
     */
    public final static byte CMD_VERSION = (byte) 0x1A;
    /**
     * 设备返回版本号
     */
    public final static byte CMD_GET_VERSION = (byte) 0x1B;
    /**
     * 发送烟名称给设备展示
     */
    public final static byte CMD_SEND_CIG_NAME = (byte) 0x1E;

    /**
     * 未鉴权
     */
    public final static int AUTH_NONE = -1;

    /**
     * 鉴权成功
     */
    public final static int AUTH_SUCCESS = 0;

    /**
     * 鉴权中
     */
    public final static int AUTH_STARTING = 1;

    /**
     * 鉴权状态
     */
    public static int mAuthStatu = AUTH_NONE;

    public static int mConnectState = BluetoothGatt.STATE_DISCONNECTED;

    /********************************  蓝牙操作 ***********************************/
    /**
     * 连接蓝牙
     *
     * @param mac
     */
    public void connect(String mac) {
        LogUtil.e("Mac:   " + mac);
        BleManager.getInstance().connect(mac, new BleGattCallback() {
            @Override
            public void onStartConnect() {
                // 开始连接
                LogUtil.e("开始连接");
                mConnectState = BluetoothGatt.STATE_CONNECTING;
                mSendHandler.sendEmptyMessage(DEVICE_START_CONNECT);
            }

            @Override
            public void onConnectFail(BleDevice bleDevice, BleException exception) {
                mConnectState = BluetoothGatt.STATE_DISCONNECTED;
                // 连接失败
                mFailHandler.sendEmptyMessage(DEVICE_START_CONNECT_FAIL);
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                // 连接成功，BleDevice即为所连接的BLE设备
//                    ToastUtils.showToastShort("蓝牙连接成功");
                mConnectState = BluetoothGatt.STATE_CONNECTED;
                Observable.timer(1000, TimeUnit.MILLISECONDS).subscribe(aLong -> {
                    BleNotify(bleDevice);
                });
            }

            @Override
            public void onDisConnected(boolean isActiveDisConnected, BleDevice bleDevice, BluetoothGatt gatt, int status) {
                LogUtil.e("----------isA: " + isActiveDisConnected + "  status: " + status);
                // 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法
                mConnectState = BluetoothGatt.STATE_DISCONNECTED;
                mFailHandler.sendEmptyMessage(DEVICE_START_DISCONNECT_FAIL);
                if (!isActiveDisConnected) {
                    Message message = new Message();
                    message.what = DEVICE_START_RECONNECT;
                    mFailHandler.sendMessageDelayed(message, 5000);
                } else {
                    reConnectTimes = 0;
                    mSendHandler.removeMessages(DEVICE_START_RECONNECT);
                }
                LogUtil.e("连接中断  ");
            }
        });
    }


    /**
     * 蓝牙设备返回
     *
     * @param bleDevice
     */
    public void BleNotify(BleDevice bleDevice) {
        BleManager.getInstance().notify(bleDevice, SERVICE_UUID, CHAR_READ_UUID, new BleNotifyCallback() {
            @Override
            public void onNotifySuccess() {
                // 打开通知操作成功
                LogUtil.e("打开通知操作成功");
                bleDevices = bleDevice;
                mSendHandler.sendEmptyMessage(DEVICE_START_AUTH);
            }

            @Override
            public void onNotifyFailure(BleException exception) {
                // 打开通知操作失败
                LogUtil.e("打开通知操作失败");
            }

            @Override
            public void onCharacteristicChanged(byte[] data) {
                // 打开通知后，设备发过来的数据将在这里出现
                LogUtil.e("收到设备通知：" + printBytes(data));
//                if (data[3] == 0x02)

                if (mAuthStatu == AUTH_SUCCESS) {
                    disposeData(data);
                } else {
                    hanlderData(data);
                }
            }
        });
    }

    private static StringBuffer buffer;

    /**
     * 发送信息给蓝牙设备
     *
     * @param bleDevice
     * @param data
     */
    public void BleWrite(BleDevice bleDevice, byte[] data) {
        if (mConnectState != BluetoothGatt.STATE_CONNECTED) {
            LogUtil.e("蓝牙尚未连接 ");
            return;
        }
        BleManager.getInstance().write(bleDevice, SERVICE_UUID, CHAR_WRITE_UUID, data, new BleWriteCallback() {
            @Override
            public void onWriteSuccess(int current, int total, byte[] justWrite) {
                // 发送数据到设备成功
                LogUtil.e("发送数据到设备成功：" + printBytes(justWrite));

                if (justWrite.length > 3 && justWrite[2] == (byte) 0x14) {
                    mSuccessHandler.sendEmptyMessage(DEVICE_SEND_14_SUC);
                }
                if (justWrite.length > 3 && justWrite[2] == (byte) 0x16) {
                    mSuccessHandler.sendEmptyMessage(DEVICE_SEND_16_SUC);
                }

            }

            @Override
            public void onWriteFailure(BleException exception) {
                if (mConnectState == BluetoothGatt.STATE_CONNECTED && data.length >= 2 && (data[2] == (byte) 0x01 || data[2] == (byte) 0x03 || data[2] == (byte) 0x05 || data[2] == (byte) 0x07)) {
                    mAuthStatu = AUTH_NONE;
                    ToastUtils.error("鉴权失败!");
                    LogUtil.e("------------鉴权出问题了: " + (data[2]));
                    buffer.append("鉴权出问题了: " + printBytes(data) + "     问题：     " + exception + "\n");
                    EventBus.getDefault().post(new EventMessage("authTest", buffer.toString() + "\n"));
                    mFailHandler.sendEmptyMessage(DEVICE_AUTH_FAIL);
                }
                // 发送数据到设备失败
                LogUtil.e("发送数据到设备失败：  " + printBytes(data), exception);
            }
        });


    }

    /********************************  发送给设备的命令 ***********************************/
    /**
     * 获取设备的香烟抽吸数据
     */
    public void getCigaretteTypeData() {
        mSendHandler.sendEmptyMessage(DEVICE_SEND_09);
    }

    /**
     * 发送手机时间给设备
     */
    public void sendDate() {
        mSendHandler.sendEmptyMessage(DEVICE_SEND_17);
    }

    /**
     * 获得设备电量
     */
    public void getElectric() {
        mSendHandler.sendEmptyMessage(DEVICE_SEND_11);
    }

    /**
     * 获取预热时间和加热温度
     */
    public void getPreheatDate() {
        mSendHandler.sendEmptyMessage(DEVICE_SEND_18);
    }

    /**
     * 发送确定收到香烟抽吸数据完成
     */
    public void sendSuccess() {
        mSendHandler.sendEmptyMessage(DEVICE_SEND_1D);
    }

    /**
     * 获取设备版本
     */
    public void getVersion() {
        mSendHandler.sendEmptyMessage(DEVICE_SEND_1A);
    }

    /**
     * 发送发热温度微调值
     */
    public void sendFever(byte[] data) {
        Message message = new Message();
        message.what = DEVICE_SEND_14;
        message.obj = data;
        mSendHandler.sendMessage(message);
    }

    public void setTemperature() {
        String value0 = MyApplication.getInstance().getUserInfo().getTemperatureTrimming();
        if (!TextUtils.isEmpty(value0)) {
            int value = Integer.parseInt(value0.replace("℃", ""));
            byte[] data = new byte[]{(byte) value};
            sendFever(data);
        }
    }

    /**
     * 发送预热时间微调值
     */
    public void sendPreheat(byte[] data) {
        Message message = new Message();
        message.what = DEVICE_SEND_16;
        message.obj = data;
        mSendHandler.sendMessage(message);
    }

    public void setPreheat() {
        String value0 = MyApplication.getInstance().getUserInfo().getTimeTrimming();
        if (!TextUtils.isEmpty(value0)) {
            int value = Integer.parseInt(value0.replace("s", ""));
            byte[] data = new byte[]{(byte) value};
            sendPreheat(data);
        }
    }

    /**
     *
     */
    public void setTrimmingData() {
        Observable.timer(1000, TimeUnit.MILLISECONDS).subscribe(aLong -> setTemperature());
        Observable.timer(2000, TimeUnit.MILLISECONDS).subscribe(aLong -> setPreheat());
    }

    /**
     * 发送设备名称
     */
    public void sendName(byte[] data) {
        Message message = new Message();
        message.what = DEVICE_SEND_13;
        message.obj = data;
        mSendHandler.sendMessage(message);
    }

    /**
     * 发送香烟类型编号、发送香烟的显示名称
     */
    public void cutCmoke(byte[] data, byte[] data0) {
        Message message = new Message();
        message.what = DEVICE_SEND_08;
        message.obj = data;
        mSendHandler.sendMessage(message);

        Message message1 = new Message();
        message1.what = DEVICE_SEND_1E;
        message1.obj = data0;
        mSendHandler.sendMessageDelayed(message1, 500);

        setTrimmingData();
    }


    public void authAgain() {
        mSendHandler.sendEmptyMessage(DEVICE_START_AUTH_AGAIN);
    }

    /**
     * 鉴权完成后的操作
     */
    public void authentication(boolean isAuthAfter) {
        //获得电量
        getElectric();
        //获取预热时间和加热温度
        Observable.timer(1000, TimeUnit.MILLISECONDS).subscribe(aLong -> getPreheatDate());
        //版本号
        Observable.timer(2000, TimeUnit.MILLISECONDS).subscribe(aLong -> getVersion());
        //发送日期
        Observable.timer(3000, TimeUnit.MILLISECONDS).subscribe(aLong -> sendDate());
        if (!isAuthAfter && AppUtils.isNetworkConnected(MyApplication.getInstance())) {
            //获取设备的香烟抽吸数据
            Observable.timer(4000, TimeUnit.MILLISECONDS).subscribe(aLong -> getCigaretteTypeData());
        }
    }


    /**
     * 鉴权
     *
     * @param value
     */
    private void hanlderData(byte[] value) {
        if (value.length < 3) {
            LogUtil.e("返回数据格式错误");
            return;
        }
        //传输格式为,0:起始字节；1：字节数量；2：命令；3~n:数据。
        switch (value[2]) {
            case CMD_RESPONSE_STATU:
                if (mAuthStatu == AUTH_STARTING && value[3] == (byte) 0x00) {
                    mSuccessHandler.sendEmptyMessage(DEVICE_AUTH_SUC);
                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        buffer.append("鉴权成功: " + printBytes(value) + "\n");
                        EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                    }
                } else {
                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        buffer.append("收到鉴权第1步数据: " + printBytes(value) + "\n");
                        EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                    }
                    mSuccessHandler.sendEmptyMessage(DEVICE_GET_1);
                }
                break;
            case CMD_RESPONSE_MD5_STR:
                mSuccessHandler.sendEmptyMessage(DEVICE_GET_4);

                if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                    buffer.append("收到鉴权第2步数据: " + printBytes(value) + "\n");
                    EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                }

                break;
            //发送运算后的md5字符
            case CMD_RESPONSE_RAW_STR2:
                Message message = new Message();
                message.what = DEVICE_GET_6;
                message.obj = value;
                mSuccessHandler.sendMessage(message);

                if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                    buffer.append("收到鉴权第3步数据: " + printBytes(value) + "\n");
                    EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                }
                break;
        }
    }

    /**
     * 处理返回有数据的
     *
     * @param value
     */
    private void disposeData(byte[] value) {
        if (value.length < 3) {
            LogUtil.e("返回数据格式错误");
            return;
        }
        //传输格式为,0:起始字节；1：字节数量；2：命令；3~n:数据。
        switch (value[2]) {
            //设备返回电量
            case CMD_RESPONSE_BATTERY:
                LogUtil.e("打印返回设备返回电量： " + printBytes(value));
                Message message = new Message();
                message.what = DEVICE_GET_12;
                message.obj = value;
                mSuccessHandler.sendMessage(message);
                break;
            //返回预热时间和加热温度
            case CMD_GET_PREHEAT:
                LogUtil.e("打印返回预热时间和加热温度： " + printBytes(value));
                Message message1 = new Message();
                message1.what = DEVICE_GET_19;
                message1.obj = value;
                mSuccessHandler.sendMessage(message1);
                break;
            //设备返回版本号
            case CMD_GET_VERSION:
                LogUtil.e("设备返回版本号： " + printBytes(value));
                Message message2 = new Message();
                message2.what = DEVICE_GET_1B;
                message2.obj = value;
                mSuccessHandler.sendMessage(message2);
                break;

            //返回设备的香烟抽吸数据
            case CMD_RESPONSE_TYPE:
                Message message3 = new Message();
                message3.what = DEVICE_GET_0A;
                message3.obj = value;
                mSuccessHandler.sendMessage(message3);
                break;

            //确定设备的香烟抽吸数据发送完成
            case GET_SUCCESS:
                mSuccessHandler.sendEmptyMessage(DEVICE_GET_1C);
                break;
        }

    }

//        public final static byte[] REQUEST_ORIENT_CAHR = new byte[]{(byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x00};


    /**
     * 发送
     */
    Handler mSendHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case DEVICE_START_CONNECT://开始链接
                    break;
                case DEVICE_START_AUTH://首次和定时鉴权,发送原始字符,返回状态，0：成功；1：错误
                    mSendHandler.sendEmptyMessage(DEVICE_SEND_2);
                    mSendHandler.sendEmptyMessageDelayed(DEVICE_START_AUTH_AGAIN, 5 * 60 * 1000);
                    break;
                case DEVICE_START_AUTH_AGAIN://再次鉴权
                    mSendHandler.removeMessages(DEVICE_START_AUTH_AGAIN);
                    mSendHandler.sendEmptyMessage(DEVICE_START_AUTH);
                    break;
                case DEVICE_SEND_2://发送MD5原始字符-->返回 DEVICE_GET_1
                    mAuthStatu = AUTH_NONE;
                    int min = 1;
                    int max = 9;
                    Random random = new Random();
                    byte[] REQUEST_CAHR = new byte[]{
                            (byte) (random.nextInt(max) % (max - min + 1) + min),
                            (byte) (random.nextInt(max) % (max - min + 1) + min),
                            (byte) (random.nextInt(max) % (max - min + 1) + min),
                            (byte) (random.nextInt(max) % (max - min + 1) + min),
                            (byte) (random.nextInt(max) % (max - min + 1) + min),
                            (byte) (random.nextInt(max) % (max - min + 1) + min),
                            (byte) (0x00)};
                    BleWrite(bleDevices, generateCmd(CMD_REQUEST_RAW_STR, REQUEST_CAHR));
                    LogUtil.e("---鉴权第一步：" + printBytes(generateCmd(CMD_REQUEST_RAW_STR, REQUEST_CAHR)));

                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        buffer.append("鉴权第1步: " + printBytes(generateCmd(CMD_REQUEST_RAW_STR, REQUEST_CAHR)) + "\n");
                        EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                    }
                    break;
                case DEVICE_SEND_3://获取MD5运算后的字符；手机发给设备
                    mAuthStatu = AUTH_STARTING;
                    BleWrite(bleDevices, generateCmd(CMD_REQUEST_MD5_STR, REQUEST_SPACHIL_CHAR));
                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        buffer.append("发送鉴权第2步: " + printBytes(generateCmd(CMD_REQUEST_MD5_STR, REQUEST_SPACHIL_CHAR)) + "\n");
                        EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                    }

                    break;
                case DEVICE_SEND_5://获取MD5原始字符；手机发给设备
                    BleWrite(bleDevices, generateCmd(CMD_REQUEST_RAW_STR2, null));
                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        buffer.append("发送鉴权第3步: " + printBytes(generateCmd(CMD_REQUEST_RAW_STR2, null)) + "\n");
                        EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                    }
                    break;
                case DEVICE_SEND_7://发送运算后的MD5字符；手机发给设备
                    byte[] data1 = parseData((byte[]) (msg.obj));
                    BleWrite(bleDevices, generateCmd(CMD_SEND_MDT_STR, getSpacilMd5(data1)));
                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        buffer.append("发送鉴权第4步: " + printBytes(generateCmd(CMD_SEND_MDT_STR, getSpacilMd5(data1))) + "\n");
                        EventBus.getDefault().post(new EventMessage("authTest", buffer.toString()));
                    }
                    break;

                case DEVICE_SEND_08://发送香烟类型编号,发送索引号
                    BleWrite(bleDevices, generateCmd(CMD_SEND_TYPE_NUMBER, (byte[]) (msg.obj)));
                    break;
                case DEVICE_SEND_09://获取设备的香烟抽吸数据
                    BleWrite(bleDevices, generateCmd(CMD_REQUEST_TYPE, null));
                    break;
                case DEVICE_SEND_11://获取剩余电量值
                    BleWrite(bleDevices, generateCmd(CMD_REQUEST_BATTERY, null));
                    break;
                case DEVICE_SEND_13://设备名称发送；手机发给设备
                    BleWrite(bleDevices, generateCmd(CMD_SEND_NAME, (byte[]) (msg.obj)));
                    break;
                case DEVICE_SEND_14://发送发热温度微调值
                    BleWrite(bleDevices, generateCmd(CMD_SEND_FEVER, (byte[]) (msg.obj)));
                    break;
                case DEVICE_SEND_16://发送预热时间微调值
                    BleWrite(bleDevices, generateCmd(CMD_PREHEAT_TIME, (byte[]) (msg.obj)));
                    break;
                case DEVICE_SEND_17://发送日期和时间值
                    int year = Integer.parseInt(DateUtils.getCurTime("yyyy"));
                    int month = Integer.parseInt(DateUtils.getCurTime("MM"));
                    int day = Integer.parseInt(DateUtils.getCurTime("dd"));
                    int hour = Integer.parseInt(DateUtils.getCurTime("HH"));
                    int minute = Integer.parseInt(DateUtils.getCurTime("mm"));
                    int second = Integer.parseInt(DateUtils.getCurTime("ss"));
                    byte[] data = new byte[]{(byte) year, (byte) 0x07, (byte) month, (byte) day, (byte) hour, (byte) minute, (byte) second};
                    BleWrite(bleDevices, generateCmd(CMD_SEND_DATE, data));
                    break;
                case DEVICE_SEND_18://获取预热时间、预热问题和加热时间、加热温度
                    BleWrite(bleDevices, generateCmd(CMD_PREHEAT, null));
                    break;
                case DEVICE_SEND_1A://获取设备的固件版本号
                    BleWrite(bleDevices, generateCmd(CMD_VERSION, null));
                    break;
                case DEVICE_SEND_1D://香烟抽吸数据接收完成,上传成功
                    BleWrite(bleDevices, generateCmd(SEND_SUCCESS, null));
                    break;
                case DEVICE_SEND_1E://发送香烟的显示名称
                    BleWrite(bleDevices, generateCmd(CMD_SEND_CIG_NAME, (byte[]) (msg.obj)));
                    break;
            }
        }
    };

    /**
     * 成功收取
     */
    private Handler mSuccessHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            User user = null;
            switch (msg.what) {
                case DEVICE_GET_1://首次发送鉴权命令成功
                    mAuthStatu = AUTH_STARTING;
                    mSendHandler.sendEmptyMessageDelayed(DEVICE_SEND_3, 500);
                    break;
                case DEVICE_GET_4://返回MD5运算后的字符；设备发给手机
                    mSendHandler.sendEmptyMessageDelayed(DEVICE_SEND_5, 500);
                    break;
                case DEVICE_GET_6://返回MD5原始字符；设备发给手机
                    Message message = new Message();
                    message.what = DEVICE_SEND_7;
                    message.obj = msg.obj;
                    mSendHandler.sendMessageDelayed(message, 500);
                    break;
                case DEVICE_AUTH_SUC://鉴权成功
                    mAuthStatu = AUTH_SUCCESS;
                    //鉴权完成后的操作
                    if (!mIsAuthAfter) {
                        ToastUtils.showToastShort("蓝牙连接成功");
                    }
                    authentication(mIsAuthAfter);
                    mIsAuthAfter = true;
                    Facility facility = MyApplication.getInstance().getDatabase().facilityDao().findByMac(bleDevices.getMac());
                    if (facility == null) {
                        facility = new Facility();
                        facility.setFacilityName(bleDevices.getName());
                        facility.setUid(MyApplication.getInstance().getUserInfo().getUid());
                        facility.setFacilityAddress(bleDevices.getMac());
                        MyApplication.getInstance().getDatabase().facilityDao().insertAllOrSingle(facility);
                    }
                    utils.saveConnectDevice(bleDevices.getMac());
                    EventBus.getDefault().post(new EventMessage("BleAuthSuccess", null));
                    break;
                case DEVICE_GET_12://返回剩余电量值
                    byte[] data = parseData2((byte[]) msg.obj);//
                    user = MyApplication.getInstance().getUserInfo();
                    user.setElectricQuantity((int) data[0]);
                    MyApplication.getInstance().getDatabase().userDao().updateUser(user);
                    EventBus.getDefault().post(new EventMessage("battery", ""));
                    break;
                case DEVICE_GET_19://返回预热时间、预热问题和加热时间、加热温度
                    ByteBuffer buf = ByteBuffer.wrap((byte[]) msg.obj);
                    byte byte1 = buf.get();
                    byte byte2 = buf.get();
                    byte byte3 = buf.get();
                    byte byte4 = buf.get();//
                    short byte56 = buf.getShort();//
                    byte byte7 = buf.get();//
                    short byte89 = buf.getShort();//

                    user = MyApplication.getInstance().getUserInfo();
                    user.setPreheatingTime(String.valueOf(byte4));
                    user.setPreheatingTemperature(String.valueOf(byte56));
                    user.setHeatingTime(String.valueOf(byte7));
                    user.setHeatingTemperature(String.valueOf(byte89));
                    MyApplication.getInstance().getDatabase().userDao().updateUser(user);
                    EventBus.getDefault().post(new EventMessage("timeTemperature", ""));
                    break;
                case DEVICE_GET_1B://返回固件版本号
                    byte[] data2 = parseData2((byte[]) msg.obj);//(int) data[0]
                    String version = "";
                    for (int i = 0; i < data2.length; i++) {
                        version += ASCUtils.backchar(data2[i]);
                    }
                    user = MyApplication.getInstance().getUserInfo();
                    user.setFacilityVersion(version);
                    MyApplication.getInstance().getDatabase().userDao().updateUser(user);
                    EventBus.getDefault().post(new EventMessage("Version", ""));
                    break;
                case DEVICE_GET_0A://返回设备的香烟抽吸数据
                    byte[] value = (byte[]) msg.obj;
                    List<String> list = new ArrayList<>();
                    List<String> list2 = new ArrayList<>();
                    for (int i = 0; i < value.length; i++) {
                        if (i > 2 && i < 11) {
                            if (i == 5) {
                                String v = "7" + String.format("%02X", value[i]);
                                int year = Integer.valueOf(v, 16);
                                list.add(year + "");
                            } else {
                                list.add(value[i] + "");
                            }
                        }
                        if (i > 10) {
                            if (i == 13) {
                                String v = "7" + String.format("%02X", value[i]);
                                int year = Integer.valueOf(v, 16);
                                list2.add(year + "");
                            } else {
                                list2.add(value[i] + "");
                            }
                        }
                    }
                    cigarettes.add(disposeCigarette(list));
                    cigarettes.add(disposeCigarette(list2));
                    break;
                case DEVICE_GET_1C://返回设备的香烟抽吸数据完成，设备发送app确认已发送完数据
                    Map<String, String> map = new ArrayMap<>();
                    LogUtil.e("------gos:  " + new Gson().toJson(cigarettes).toString());
                    map.put("experience", new Gson().toJson(cigarettes));
                    EventBus.getDefault().post(new EventMessage("CigaretteData", map));
                    break;
                case DEVICE_SEND_14_SUC:
                    EventBus.getDefault().post(new EventMessage("CMD_SEND_FEVER", ""));
                    break;
                case DEVICE_SEND_16_SUC:
                    EventBus.getDefault().post(new EventMessage("CMD_PREHEAT_TIME", ""));
                    break;
            }
        }
    };


    /**
     * 发送失败
     */
    private Handler mFailHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case DEVICE_START_CONNECT_FAIL://蓝牙连接失败
                    if (reConnectTimes == 0) {
                        ToastUtils.error("蓝牙连接失败,请重新尝试!");
                        reConnectTimes++;
                    }
                    mAuthStatu = AUTH_NONE;
                    mIsAuthAfter = false;
                    mSendHandler.removeMessages(DEVICE_START_AUTH_AGAIN);
                    EventBus.getDefault().post(new EventMessage("connectFail", ""));
                    break;
                case DEVICE_START_DISCONNECT_FAIL://蓝牙连接断开
                    mAuthStatu = AUTH_NONE;
                    mIsAuthAfter = false;
                    MyApplication.getInstance().resetUserInfo();
                    mSendHandler.removeMessages(DEVICE_START_AUTH_AGAIN);
                    EventBus.getDefault().post(new EventMessage("onDisConnected", ""));
                    break;
                case DEVICE_START_RECONNECT://重连
                    if (mConnectState == BluetoothGatt.STATE_CONNECTED) {
                        reConnectTimes = 0;
                        mFailHandler.removeMessages(DEVICE_START_RECONNECT);
                    } else {
                        LogUtil.e("-------bb: " + bleDevices);
                        if (bleDevices != null) {
                            connect(bleDevices.getMac());
                            mFailHandler.removeMessages(DEVICE_START_RECONNECT);
                            mFailHandler.sendEmptyMessageDelayed(DEVICE_START_RECONNECT, 10000);
                        }
                    }
                    break;
                case DEVICE_AUTH_FAIL://鉴权失败
                    if (bleDevices != null) {
                        BleManager.getInstance().disconnect(bleDevices);
                    }
                    EventBus.getDefault().post(new EventMessage("AuthFail", ""));
                    break;
                case DEVICE_SEND_2://发送MD5原始字符-->返回 DEVICE_GET_1
                    break;
                case DEVICE_SEND_3://获取MD5运算后的字符；手机发给设备
                    break;
                case DEVICE_SEND_5://获取MD5原始字符；手机发给设备
                    break;
                case DEVICE_SEND_7://发送运算后的MD5字符；手机发给设备
                    break;
                case DEVICE_SEND_08://发送香烟类型编号,发送索引号
                    break;
                case DEVICE_SEND_09://获取设备的香烟抽吸数据
                    break;
                case DEVICE_SEND_11://获取剩余电量值
                    break;
                case DEVICE_SEND_13://设备名称发送；手机发给设备
                    break;
                case DEVICE_SEND_14://发送发热温度微调值
                    break;
                case DEVICE_SEND_16://发送预热时间微调值
                    break;
                case DEVICE_SEND_17://发送日期和时间值
                    break;
                case DEVICE_SEND_18://获取预热时间、预热问题和加热时间、加热温度
                    break;
                case DEVICE_SEND_1A://获取设备的固件版本号
                    break;
                case DEVICE_SEND_1D://香烟抽吸数据接收完成,上传成功
                    break;
                case DEVICE_SEND_1E://发送香烟的显示名称
                    break;
            }
        }
    };


    public void disconnect() {
        try {
            LogUtil.e("--------断开了0" + bleDevices + ":   " + BleManager.getInstance().isConnected(bleDevices));
            BleManager.getInstance().disconnect(bleDevices);
            LogUtil.e("--------断开了1" + bleDevices + ":   " + BleManager.getInstance().isConnected(bleDevices));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取md5加密后，15/4/7/9/10/8/13/11位置的字符
     *
     * @param src
     * @return
     */
    public byte[] getSpacilMd5(byte[] src) {
        int len = 0;
        byte[] dest = new byte[8];
        byte[] md5 = getMd5(src);

        dest[len++] = md5[15];
        dest[len++] = md5[4];
        dest[len++] = md5[7];
        dest[len++] = md5[9];
        dest[len++] = md5[10];
        dest[len++] = md5[8];
        dest[len++] = md5[13];
        dest[len++] = md5[11];
        return dest;
    }

    /**
     * 获取md5加密后，0、2、4、5、6、6位置的字符
     *
     * @param src
     * @return
     */
    public byte[] getSpacilMd5_6(byte[] src) {
        int len = 0;
        byte[] dest = new byte[6];
        byte[] md5 = getMd5(src);

        dest[len++] = md5[0];
        dest[len++] = md5[2];
        dest[len++] = md5[4];
        dest[len++] = md5[5];
        dest[len++] = md5[6];
        dest[len++] = md5[6];
        return dest;
    }

    /**
     * 打印字节
     *
     * @param value
     */
    public String printBytes(byte[] value) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < value.length; i++) {
            sb.append(String.format("%02X", value[i]) + " ");
        }
        return sb.toString();
    }


    /**
     * 解析通讯里的数据
     *
     * @param value
     * @return
     */
    public byte[] parseData(byte[] value) {
        if (value == null || value.length < 4) {
            LogUtil.e("数据格式不正确");
            return null;
        }
        byte[] temp = new byte[value.length - 3];
        System.arraycopy(value, 2, temp, 0, temp.length);
        return temp;
    }

    /**
     * 解析鉴权成功后的数据
     *
     * @param value
     * @return
     */
    public byte[] parseData2(byte[] value) {
        if (value == null || value.length < 4) {
            LogUtil.e("数据格式不正确");
            return null;
        }
        byte[] temp = new byte[value.length - 3];
        System.arraycopy(value, 3, temp, 0, temp.length);
        return temp;
    }


    public byte[] getMd5(byte[] src) {

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < src.length; i++) {
            if (i == 0) {
                continue;
            }
            sb.append((char) src[i]);
        }
        byte[] result = MD5Utils.MD5_32(sb.toString());
        return result;
    }

    public byte[] generateCmd(byte cmd, byte[] data) {
        // byte[] result = new byte[]{(byte) 0xff, (byte) 0x01, (byte) 0x11};
        int dataLen = 3;
        if (data != null) {
            dataLen += data.length;
        }
        byte[] result = new byte[dataLen];
        int len = 0;
        result[len++] = (byte) 0xff;
        if (data != null) {
            result[len++] = (byte) (data.length + 1);
        } else {
            result[len++] = (byte) 0x01;
        }
        result[len++] = cmd;
        if (data != null) {
            for (byte b : data) {
                result[len++] = b;
            }
        }
        return result;
    }


    /**
     * 处理设备返回的香烟抽吸数据
     *
     * @param list
     * @return
     */
    public Cigarette disposeCigarette(List<String> list) {
        Cigarette cigarette = new Cigarette();
        cigarette.setUid(MyApplication.getInstance().getUserInfo().getUid());
        for (int i = 0; i < list.size(); i++) {
            if (i < 2) {
                String day = list.get(i);
                if (day.length() == 1) {
                    day = "0" + day;
                }
                cigarette.setIndexes(cigarette.getIndexes() == null ? day : cigarette.getIndexes() + day);
            } else if (i < list.size() - 1) {
                String day = list.get(i);
                if (day.length() == 1) {
                    day = "0" + day;
                }
                if (i < 5) {
                    cigarette.setCtime(cigarette.getCtime() == null ? day : cigarette.getCtime() + "-" + day);
                } else {
                    cigarette.setCtime(i == 5 ? cigarette.getCtime() + " " + day : cigarette.getCtime() + ":" + day);
                }
            } else {
                cigarette.setTimes(list.get(i));
            }
        }
        return cigarette;
    }
}
